#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <linux/sockios.h>
#include <net/route.h>
#include <errno.h>
#include <stdbool.h>
#include "socktool.h"
#include <fcntl.h>
#include <sys/time.h>

/*
 * 获取指定IP对应网卡的MAC地址
 * @eth_name: 网卡名, 如:eth0, wlan0..
 * @ip: 需要查询的IP地址
 * @mac: 返回6字节mac地址, 如unsigned char mac[6] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB};
 * @ret: 0: 成功, -1: 失败
 */
int net_eth_dst_get_mac(const char *eth_name, char *ip, unsigned char *mac)
{
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    if (sockfd < 0) {
        perror("socket");
        return -1;
    }

    struct arpreq arp_req;
    memset(&arp_req, 0, sizeof(arp_req));
    struct sockaddr_in *sin = (struct sockaddr_in *)&arp_req.arp_pa;
    sin->sin_family = AF_INET;
    memcpy(&(sin->sin_addr), ip, 4);
    strcpy(arp_req.arp_dev, eth_name);

    if (ioctl(sockfd, SIOCGARP, &arp_req) < 0) {
        perror("ioctl");
        close(sockfd);
        return -1;
    }

	memcpy(mac, arp_req.arp_ha.sa_data, 6);

    printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 
           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

    close(sockfd);
    return 0;
}

/*
 * 获取网卡的MAC地址
 * @eth_name: 网卡名, 如:eth0, wlan0..
 * @mac: 返回6字节mac地址, 如unsigned char mac[6] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB};
 * @ret: 0: 成功, -1: 失败
 */
int net_eth_get_mac(const char *eth_name, unsigned char *mac)
{
	int ret;
	int fd;
	struct ifreq ifreq;
 
	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
 
	memset(&ifreq, 0x00, sizeof(struct ifreq));
 
	strcpy(ifreq.ifr_name, eth_name);
	ret = ioctl(fd, SIOCGIFHWADDR, &ifreq);
 
	if (ret < 0) {
		perror("SIOCGIFHWADDR: ");
	}
 
	if (ret == 0 && ifreq.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
		memcpy(mac, ifreq.ifr_hwaddr.sa_data, 6);
	} else {
		ret = -1;
	}
	
	close(fd);
 
	return ret;
}

/*
 * 修改网卡的MAC地址
 * @eth_name: 网卡名, 如:eth0, wlan0..
 * @mac: 6字节mac地址, 如unsigned char mac[6] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB};
 *       类似于 ifconfig ethx hw ether 12:34:56:78:90:AB
 * @ret: 0: 成功, -1: 失败
 */
int net_eth_set_mac(const char *eth_name, unsigned char *mac)
{
	int ret;
	int fd;
	short flag;
	struct ifreq ifreq;
 
	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
 
	memset(&ifreq, 0x00, sizeof(struct ifreq));
	strcpy(ifreq.ifr_name, eth_name);
 
	ret = ioctl(fd, SIOCGIFFLAGS, &ifreq);
 
	if (ret < 0) {
		ret = -1;
		perror("SIOCGIFFLAGS: ");
		goto ERROR;
	}
 
	flag = ifreq.ifr_flags;
 
	/*
	 * 如果网卡是启动的,设置MAC地址需要先停止网卡
	 */
	if (flag & IFF_UP) {
		ifreq.ifr_flags &= ~IFF_UP;
		ioctl(fd, SIOCSIFFLAGS, &ifreq);
	}
 
	/*
	 * 配置MAC地址
	 */
	ifreq.ifr_hwaddr.sa_family = ARPHRD_ETHER;
	memcpy(ifreq.ifr_hwaddr.sa_data, mac, 6);
	ret = ioctl(fd, SIOCSIFHWADDR, &ifreq);
 
	if (ret < 0) {
		ret = -1;
		perror("SIOCSIFHWADDR: ");
		goto ERROR;
	}
 
	/*
	 * 如果恢复网卡的工作状态
	 */
	if (flag & IFF_UP) {
		ioctl(fd, SIOCGIFFLAGS, &ifreq);
		ifreq.ifr_flags |= IFF_UP;
		ioctl(fd, SIOCSIFFLAGS, &ifreq);
	}
 
ERROR:	
	close(fd);
 
	return ret;
}

/*
 * 获取网卡ip地址
 * @eth_name: 网卡名, 如:eth0, wlan0..
 * @ip: 返回4字节ip地址, 如char ip[4] = {10, 10, 10, 3};即: 10.10.10.3
 * @netmask: 返回4字节netmask地址, 如char netmask[4] = {0xff, 0xff, 0xff, 0};即: 255.255.255.0
 * @ret: 0: 成功, -1: 不能获取ip地址
 */
int net_eth_get_ipv4_addr(const char *eth_name, unsigned char *ip, unsigned char *netmask)
{
	int ret;
	int fd;
	struct ifreq ifreq;
 
	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
 
	memset(&ifreq, 0x00, sizeof(struct ifreq));
	strcpy(ifreq.ifr_name, eth_name);
 
	/*
	 * 获取IP地址
	 */
	ret = ioctl(fd, SIOCGIFADDR, &ifreq);
 
	if (ret < 0) {
		ret = -1;
		perror("SIOCGIFADDR: ");
		goto ERROR;
	}
 
	if (ifreq.ifr_addr.sa_family != AF_INET) {
		ret = -1;
		goto ERROR;
	}
 
	struct sockaddr_in *addr = (struct sockaddr_in *)&(ifreq.ifr_addr);
	memcpy(ip, &(addr->sin_addr.s_addr), 4);
 
 
	/*
	 * 获取netmask
	 */
	ret = ioctl(fd, SIOCGIFNETMASK, &ifreq);
 
	if (ret < 0) {
		ret = -1;
		perror("SIOCGIFNETMASK: ");
		goto ERROR;
	}
 
	if (ifreq.ifr_netmask.sa_family != AF_INET) {
		ret = -1;
		goto ERROR;
	}
 
	addr = (struct sockaddr_in *)&(ifreq.ifr_netmask);
	memcpy(netmask, &(addr->sin_addr.s_addr), 4);
 
ERROR:
	close(fd);
 
	return ret;
}
 
/*
 * 设置网卡ip地址
 * @eth_name: 网卡名, 如:eth0, wlan0..
 * @ip: 返回4字节ip地址, 如char ip[4] = {10, 10, 10, 3};即: 10.10.10.3
 * @netmask: 返回4字节netmask地址, 如char netmask[4] = {0xff, 0xff, 0xff, 0};即: 255.255.255.0
 * @ret: 0: 成功, -1: 不能获取ip地址
 */
int net_eth_set_ipv4_addr(const char *eth_name, unsigned char *ip, unsigned char *netmask)
{
	int ret = 0;
	int fd;
	struct ifreq ifreq;
 
	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
 
	memset(&ifreq, 0x00, sizeof(struct ifreq));
	strcpy(ifreq.ifr_name, eth_name);
 
	/*
	 * 设置IP地址
	 */
	ifreq.ifr_addr.sa_family = AF_INET;
	struct sockaddr_in *addr = (struct sockaddr_in *)&(ifreq.ifr_addr);
	memcpy(&(addr->sin_addr.s_addr), ip, 4);
	ret = ioctl(fd, SIOCSIFADDR, &ifreq);
	if (ret < 0) {
		ret = -1;
		perror("SIOCSIFADDR: ");
		goto ERROR;
	}
 
	/*
	 * 获取netmask
	 */
	ifreq.ifr_netmask.sa_family = AF_INET;
	addr = (struct sockaddr_in *)&(ifreq.ifr_netmask);
	memcpy(&(addr->sin_addr.s_addr), netmask, 4);
	ret = ioctl(fd, SIOCSIFNETMASK, &ifreq);
	if (ret < 0) {
		ret = -1;
		perror("SIOCSIFNETMASK: ");
		goto ERROR;
	}
ERROR:
	close(fd);
 
	return ret;
}


/*
 * 添加默认网关
 * @gw: 4字节地址, 如char gw[4] = {10, 10, 10, 1};即: 10.10.10.1
 * @ret: 0: 成功, -1: 失败
 * 
 * 注意: 如果想删除网卡相关的所有路由表可以直接把网卡down,即ifconfig ethx down
 */
int net_route_add_default_gateway(const char *eth_name, unsigned char *gw) 
{
    int fd;
	struct sockaddr_in *sin;

	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (fd < 0) {
        perror("socket");
        return -1;
    }
 
    struct rtentry route;
    memset(&route, 0, sizeof(route));
    route.rt_flags = RTF_UP | RTF_GATEWAY;
    route.rt_dev = (char*)eth_name;

    sin = (struct sockaddr_in *)&(route.rt_dst);
    sin->sin_family = AF_INET;
 
    sin = (struct sockaddr_in *)&(route.rt_gateway);
    sin->sin_family = AF_INET;
	memcpy(&(sin->sin_addr.s_addr), gw, 4);

    sin = (struct sockaddr_in *)&(route.rt_genmask);
    sin->sin_family = AF_INET;
 
    if (ioctl(fd, SIOCADDRT, &route) < 0) {
        perror("SIOCADDRT");
        close(fd);
        return -1;
    }
 
    close(fd);
    return 0;
}

/*
 * 删除默认网关
 * @gw: 4字节地址, 如char gw[4] = {10, 10, 10, 1};即: 10.10.10.1
 * @ret: 0: 成功, -1: 失败
 * 
 * 注意: 如果想删除网卡相关的所有路由表可以直接把网卡down,即ifconfig ethx down
 */
int net_route_del_default_gateway(const char *eth_name, unsigned char *gw) 
{
    int fd;
	struct sockaddr_in *sin;

	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (fd < 0) {
        perror("socket");
        return -1;
    }
 
    struct rtentry route;
    memset(&route, 0, sizeof(route));
    route.rt_flags = RTF_UP | RTF_GATEWAY;
    route.rt_dev = (char*)eth_name;

    sin = (struct sockaddr_in *)&(route.rt_dst);
    sin->sin_family = AF_INET;
 
    sin = (struct sockaddr_in *)&(route.rt_gateway);
    sin->sin_family = AF_INET;
	memcpy(&(sin->sin_addr.s_addr), gw, 4);

    sin = (struct sockaddr_in *)&(route.rt_genmask);
    sin->sin_family = AF_INET;
 
    if (ioctl(fd, SIOCDELRT, &route) < 0) {
        perror("SIOCDELRT");
        close(fd);
        return -1;
    }
 
    close(fd);
    return 0;
}

/*
 * 获取默认网关
 * @eth_name: 网卡名, 如:eth0, wlan0..
 * @gw: 获取4字节地址, 如char gw[4] = {10, 10, 10, 1};即: 10.10.10.1
 * @ret: 0: 成功, -1: 失败
 * 
 * 注意: 如果想删除网卡相关的所有路由表可以直接把网卡down,即ifconfig ethx down
 */
int net_route_get_default_gateway(const char *eth_name, unsigned char *gw)
{
	int ret = -1;
	FILE *fp;
	char devname[64];
	unsigned long d, g, m;
	int r;
	int flgs, ref, use, metric, mtu, win, ir;
 
	fp = fopen("/proc/net/route", "r");
 
	/* Skip the first line. */
	r = fscanf(fp, "%*[^\n]\n");
 
	if (r < 0) {
		/* Empty line, read error, or EOF. Yes, if routing table
		 * is completely empty, /proc/net/route has no header.
		 */
		ret = -1;
		goto ERROR;
	}
 
	while (1) {
		r = fscanf(fp, "%63s%lx%lx%X%d%d%d%lx%d%d%d\n",
				devname, &d, &g, &flgs, &ref, &use, &metric, &m,
				&mtu, &win, &ir);
 
		if (r != 11) {
			if ((r < 0) && feof(fp)) { /* EOF with no (nonspace) chars read. */
				break;
			}
		}
 
		/*
		 * # cat /proc/net/route 
		 * Iface   Destination     Gateway         Flags   RefCnt  Use     Metric  Mask            MTU     Window  IRTT                                                       
		 * eth0    00000000        013CA8C0        0003    0       0       0       00000000        0       0       0                                                                               
		 * eth0    003CA8C0        00000000        0001    0       0       0       00FFFFFF        0       0       0
		 * 默认网关的特性: dst为0，netmask为0, Gateway不为0
		 */
		if (strcmp(devname, eth_name) == 0 &&\
			(flgs & RTF_GATEWAY) && \
			(flgs & RTF_UP) && \
			g != 0 && d == 0 && m == 0) {
			memcpy(gw, &g, 4);
			ret = 0;
			break;
		}
	}
 
ERROR:
	fclose(fp);
	return ret;
}
